#include "Graphics/gpuprefabs.h"
#include "Graphics/gpurenderer.h"
#include "SDL3_image/SDL_image.h"


using namespace Jin;

struct AppContext final {

	enum {
		WIN_WIDTH = 800,
		WIN_HEIGHT = 600,
		WIN_FLAGS = 0,
	};

	SDLFramework sdlfx;
	SDLWindowUPtr mainWindow;
	GPURendererUPtr renderer;
	GPUTextureSPtr screen;
	GPUTextureSPtr texture;
	Point2DF position;

	AppContext() = default;
	~AppContext() = default;
	bool Init();
	void Run();
	void Cleanup();

private:
	bool _CreateMainWindow() {
		mainWindow = std::make_unique<SDLWindow>("testGPURnederer", WIN_WIDTH, WIN_HEIGHT, WIN_FLAGS);
		if (!*mainWindow) {
			return false;
		}
		sdlfx.SetFPS(200);
		sdlfx.onFPS = [this](Uint32 fps) {
			mainWindow->SetTitle(std::format("fps:{}, delta:{}", fps, sdlfx.deltaTime).c_str());
			};
		return true;
	}
	bool _CreateGPURenderer() {
		if (renderer = std::make_unique<GPURenderer>(*mainWindow); !*renderer) {
			return false;
		}
		(*renderer)->SetSwapchainParameters(SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_IMMEDIATE);
		if (screen = std::make_shared<GPUTexture>(*renderer, WIN_WIDTH, WIN_HEIGHT, SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE); !*screen) {
			return false;
		}
		if (texture = std::make_shared<GPUTexture>(*renderer, "images/girl.png"); !*texture) {
			return false;
		}
		texture->ctdBlendMode = CTD_BLENDMODE_BLEND;
		texture->colorMod.a = 0.5f;
		//texture->colorModType = COLORMODTYPE_DOT;
		//texture->colorMod = { 0.299, 0.587, 0.114, 0.5f };
		return true;
	}
	void _UpdateData() {
	}
};

bool AppContext::Init() {
	if (!_CreateMainWindow()) {
		return false;
	}
	if (!_CreateGPURenderer()) {
		return false;
	}
	SDL_srand(0);

	_UpdateData();
	return true;
}

void AppContext::Run() {
	static float angle = 0.0f;
	sdlfx.onFrame = [this]() {
		if (mainWindow->GetWindowFlags() & SDL_WINDOW_MINIMIZED) {
			return;
		}
		renderer->SetRenderTarget(screen);
		renderer->SetViewport(Rect2DF{ 200, 200, 300, 300 });
		renderer->SetDrawColor(0xffffffff_abgr);
		renderer->FillRect(Rect2DF{ 100, 100 });
		//renderer->RenderClear();
		renderer->SetDrawColor(0xff4080ff_abgr);
		renderer->DrawLine(10, 10, 100, 100);
		renderer->SetPointParam({ 40.0f });
		renderer->SetPointStyle(POINTSTYLE_SQUAREPOINT);
		renderer->DrawPoint(200, 200);
		renderer->SetPointParam({ 30.0f });
		renderer->SetPointStyle(POINTSTYLE_CIRCLEPOINT);
		renderer->DrawPoint(300, 200);
		renderer->SetPointStyle(POINTSTYLE_SQUAREPOINT);
		renderer->DrawPoint(300, 300);
		renderer->SetPointStyle(POINTSTYLE_CIRCLEPOINT);
		renderer->DrawPoint(300, 400);
		renderer->SetPointStyle(POINTSTYLE_SQUAREPOINT);
		renderer->DrawPoint(400, 400);
		renderer->SetDrawBlendMode(SDL_BLENDMODE_BLEND);
		renderer->SetDrawColor(0x400000ff_abgr);
		renderer->SetLineThicknessParam({.thickness = 10.0f, .lineCap = 1 });
		renderer->DrawLineThickness(150, 150, 550, 550);
		//renderer->DrawRect(Rect2DF{ 10, 10 });
		angle += sdlfx.deltaTime / 20.0f;
		renderer->RenderTexture(texture, nullptr, Rect2DF{position, {256, 256}}, angle * 360, {128, 128}, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL);
		renderer->DrawRect(Rect2DF{ position + Point2DF{128,128}, {50, 50} });
		renderer->SetFilterMode(FILTERMODE_GRAYSCALE);
		renderer->FilterRect(Rect2D{ Point2D{(int)position.x + 128, (int)position.y + 128}, {50,50} });
		renderer->SetRenderTarget(nullptr);
		renderer->RenderTexture(screen, nullptr, nullptr);
		renderer->RenderPresent();
	};
	sdlfx.onEvent = [this](EventData& event) {
		if (event.type == SDL_EVENT_KEY_DOWN) {
			if (event.key.key == SDLK_D) {
				auto surface = renderer->ReadPixels(nullptr);
				if (surface) {
					IMG_SavePNG(*surface, "images/save.png");
				}
			}
		}
		else if (event.type == SDL_EVENT_MOUSE_MOTION) {
			position = { event.motion.x - 200 - 128, event.motion.y - 200 - 128 };
		}
		return true;
	};
	sdlfx.Run();
}

void AppContext::Cleanup() {
}

int main() {
	try {
		AppContext app;
		if (app.Init()) {
			app.Run();
		}
		app.Cleanup();
	}
	catch (const std::exception& e) {
		SDL_LogError(0, "App error! '%s'", e.what());
		return -1;
	}
	return 0;
}
